﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Threading.Tasks;
using System.Windows.Threading;

namespace SQLDataTransferer.Common.Dialogs
{
    /// <summary>
    /// Interaction logic for ProgressDialog.xaml
    /// </summary>
    public partial class ProgressDialog : Window
    {
        #region Contructor(s)

        /// <summary>
        /// Inits the dialog with a given dialog text.
        /// </summary>
        public ProgressDialog(string dialogText)
            : this()
        {
            this.DialogText = dialogText;
        }

        /// <summary>
        /// Inits the dialog without displaying it.
        /// </summary>
        public ProgressDialog()
        {
            InitializeComponent();
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the dialog text.
        /// </summary>
        public string DialogText
        {
            get { return this.txtDialogMessage.Text; }
            set { this.txtDialogMessage.Text = value; }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The WPF way of Application.DoEvents()
        /// <see cref="http://www.cnblogs.com/sheva/archive/2006/08/24/485790.html"/>
        /// </summary>
        private void DoEvents()
        {
            // Create new nested message pump.
            DispatcherFrame dispatcherFrame = new DispatcherFrame();

            // Dispatch a callback to the current message queue, when getting called, 
            // this callback will end the nested message loop.
            // note that the priority of this callback should be lower than the that of UI event messages.
            var exitOperation = Dispatcher
                                .CurrentDispatcher
                                .BeginInvoke(DispatcherPriority.Background,
                                             new DispatcherOperationCallback(stateObject =>
                                             {
                                                 var frame = stateObject as DispatcherFrame;
                                                 // Exit the nested message loop.
                                                 frame.Continue = false;
                                                 return null;
                                             }),
                                             dispatcherFrame);

            // pump the nested message loop, the nested message loop will 
            // immediately process the messages left inside the message queue.
            Dispatcher.PushFrame(dispatcherFrame);

            // If the "exitFrame" callback doesn't get finished, Abort it.
            if (exitOperation.Status != DispatcherOperationStatus.Completed)
                exitOperation.Abort();
        }

        /// <summary>
        /// Runs an Action delegate using the Paralel Task Library
        /// </summary>
        /// <param name="taskAction">The action to invoke</param>
        /// <returns></returns>
        /// w<see cref="http://nitoprograms.blogspot.com/2010/06/reporting-progress-from-tasks.html"/>
        public bool RunTask(Action taskAction)
        {
            var task = new Task(() =>
            {
                // Make sure the UI is shown when progressing is really fast
                //System.Threading.Thread.Sleep(500);

                taskAction.BeginInvoke(new AsyncCallback((iResult) =>
                {
                    var pBar = iResult.AsyncState as ProgressBar;

                    pBar.Dispatcher.Invoke(
                        new Action(() =>
                        {
                            //TODO: use a timer or something instead of current test code to simulate the progress
                            for (int i = 0; i <= 100; i++)
                            {
                                pBar.Value++;
                                DoEvents();
                                System.Threading.Thread.Sleep(10);
                            }

                            this.Dispatcher.Invoke(new Action(() => { this.Close(); }));
                        }));
                }), this.progressBar);
            });

            // Pushes the task into the TaskScheduler queue
            task.Start();

            return this.ShowDialog() ?? false;
        }

        #endregion

        #region EventHandlers

        private void btnCancel_Click(object sender, RoutedEventArgs e)
        {
            //TODO:
            // if(task.Status == TaskStatus.Running)

            this.Close();
        }

        #endregion
    }
}
